#include "Thread.h"
#include "Threadpool.h"
#include <unistd.h>

Threadpool::Threadpool(size_t threadNum, size_t queSize)
: _threadNum(threadNum)
, _queSize(queSize)
, _taskQue(_queSize)
, _isExit(false)
{
    //预留空间
    _threads.reserve(_threadNum);
}

Threadpool::~Threadpool()
{

}

void Threadpool::start()
{
    //1、将子线程创建出来，然后存放在vector中
    for(size_t idx = 0; idx < _threadNum; ++idx)
    {
        //就是线程池交给每一个子线程做的任务，也就是线程池中threadFunc函数
        unique_ptr<Thread> up(new Thread(std::bind(&Threadpool::threadFunc, this)));
        _threads.push_back(std::move(up));
    }
    //2、遍历vector，将所有的子线程运行起来
    for(auto &th : _threads)
    {
        th->start();//让所有的子线程都运行起来
    }
}

void Threadpool::stop()
{
    //应该判断一下任务队列中还有没有任务没有执行如果有任务没有
    //执行，那么工作线程是不能退出来的
    while(!_taskQue.empty())
    {
        sleep(1);
    }
    _isExit = true;

    //将所有可能等待在_notEmpty条件变量上的线程全部唤醒
    _taskQue.wakeup();

    //将线程池中所有子线程（工作线程）停止
    for(auto &th : _threads)
    {
        th->join();//让所有的子线程都停止
    }
}

void Threadpool::addTask(Task &&task)
{
    if(task)
    {
        _taskQue.push(std::move(task));
    }
}

Task Threadpool::getTask()
{
    return _taskQue.pop();

}

//线程池交给子线程做的任务
void Threadpool::threadFunc()
{
    //只要线程池不退出，那么子线程就需要一直做任务
    while(!_isExit)
    {
        //如果getTask执行的速度非常快，那么会继续走while循环，先判断
        //_isExit是不是true，但是此时stop中对于_isExit的设置比较慢的
        //话，那么线程会继续进到while中拿任务，如果此时任务队列中
        //没有任务，那么getTask就会阻塞;但是如果getTask执行的速度非常
        //的慢，那么stop中是有机会将_isExit设置为true，那么当任务执行
        //完毕之后，while循环的判断条件就是false，那么代码就进不到
        //while，就不会出现阻塞现象
        Task taskcb = getTask();
        if(taskcb)
        {
            taskcb();//执行任务
        }
    }
}

